﻿using UnityEngine;
using System.Collections;

public class Character : MonoBehaviour {

    public int PlayerInd = 0;
    public Material SecMat;
	[HideInInspector] public Rigidbody Body;
    [HideInInspector] public Transform Trnsfrm;
    [HideInInspector] public Animator Anim;
    [HideInInspector] public CapsuleCollider Col;
	public GameObject DeathEffects;
	public GameObject SpeedEffects;

	void Start(){
		DeathEffects.SetActive(false);
		SpeedEffects.SetActive(false);
	}

	void Awake () {
	    Body = rigidbody;
        Trnsfrm = transform;
        Anim = GetComponent<Animator>();
        Col = GetComponent<CapsuleCollider>();

        GroundMask = -1;// ^ (1<<LayerMask.NameToLayer("Player"));
        InvulTimer = Time.time +2.0f;

        set(PlayerInd);

	}
    public void shove(Vector3 frc, Vector3 at) {
            
        ForceTimer = Time.time +0.75f;
        if( InvulTimer > Time.time ) {
            frc *= 0.2f;
            ForceTimer = Mathf.Min(ForceTimer,InvulTimer);
        }  
           
        Body.AddForceAtPosition( frc, at );
    }

    public void set(int i) {
        PlayerInd = i;
        if(PlayerInd != 0) { 
            Trnsfrm.eulerAngles = new Vector3(0,0,180.0f);
            foreach( MeshRenderer mr in GetComponentsInChildren<MeshRenderer>() )
                mr.material = SecMat;
        }
        JumpFrc *=Mathf.Sign(Trnsfrm.up.y);
        Gravity *=Mathf.Sign(Trnsfrm.up.y);
    }

    public float MaxSpeed = 5.0f;
    public float Accel = 2000.0f;
    public float JumpFrc = 500.0f;
    public float Gravity = -9.8f *100.0f ;
	public AudioClip DeathSound;
	public AudioClip JumpSound;

    public PhysicMaterial TypPhysMat;

    void Update() {
       if(Dead) {
           Anim.SetBool("Grounded",false );
			if(JumpTimer <Time.time) {
               if(PlayerInd != -1) { 
                    Camera.main.GetComponent<CameraScript>().respawn(PlayerInd);
                   PlayerInd = -1;
               } else if(JumpTimer+100.0f <Time.time) { 
                   Destroy( gameObject );
               }
           }
           var sp = Camera.main.WorldToViewportPoint( Trnsfrm.position );
           if( sp.x < 0) Body.AddForce(new Vector3(500.0f,Random.Range(-100,100.0f),0) );
           return;
        }
        Anim.SetBool("Crouch",  Crouched = Input.GetButton("Crouch"+PlayerInd) );
        if(Input.GetButtonDown("Jump"+PlayerInd)) {
			audio.PlayOneShot(JumpSound);
            JumpPls = Time.time+0.2f;
        }

        
    }
    float JumpPls = -1;

    int GroundMask;
    void FixedUpdate() {

        if(Dead) {              
            Body.AddForce( Vector3.up*Gravity*Time.deltaTime *0.3f );
			StartCoroutine(DeadSplatter());
            return;
        }
        var up = Trnsfrm.up;
        bool grounded = false;
        foreach(RaycastHit hit in  Physics.SphereCastAll( new Ray(Trnsfrm.position -up*(Col.height*0.5f-Col.radius),-up), 0.45f,0.2f,GroundMask) ) {
          //  Debug.Log("hit "+hit.normal +hit.point +name +hit.collider.name);
            if( Vector3.Dot(up,hit.normal) >0.3f ) grounded = true;
            switch(hit.collider.gameObject.layer ) {
                case 8 : 
                    SlowTimer = 0.1f;
                    break;

            }
        }
        Anim.SetBool("Grounded",grounded );
        if( grounded ) GroundFrameCnt = Mathf.Min( GroundFrameCnt+1,4 );
        else GroundFrameCnt = Mathf.Max( GroundFrameCnt-1,0 );

        var acc = Input.GetAxis("Horizontal"+PlayerInd) *Accel;
		if(IsInvert == true){
			float OriginalAcc = acc;
			acc = OriginalAcc * -1;
		}
        Anim.SetFloat( "Speed", Mathf.Abs(acc) );

        var cmp = acc; if(PlayerInd!=0) cmp = -cmp;
        if(cmp > 0.1f ) {
            Trnsfrm.rotation = Quaternion.LookRotation( Vector3.forward,Trnsfrm.up );
        } else if(cmp <-0.1f) {
            Trnsfrm.rotation = Quaternion.LookRotation( Vector3.back,Trnsfrm.up );
        } 

        if(Crouched) {
            acc *= 0.15f;

            JumpTimer = Time.time+0.1f;
        }
        float vel = Body.velocity.x/MaxSpeed;
        if(SlowTimer > 0.0f) {
            vel *= 2.0f;
            SlowTimer -= Time.deltaTime;
        } 
        var absVel = Mathf.Abs(vel);
 
        if( Mathf.Sign( acc) == Mathf.Sign(vel)   ){
            acc *= Mathf.Max(0.0f,1.0f - absVel*absVel);
        }
        var frc = new Vector3( acc*Time.deltaTime,0,0);


        if(grounded) {
            if((acc == 0.0f || Mathf.Sign( acc) != Mathf.Sign(vel) ) || Crouched ) {
                var mod = Accel*Time.deltaTime;
                if( Crouched ) mod *= 0.1f;
                frc.x -= Mathf.Clamp(vel *2.0f, -1,1 ) *mod;
            }
            if( GroundFrameCnt >3 && JumpPls>Time.time && JumpTimer < Time.time ) {
                JumpTimer = Time.time +0.4f;

                var v= Body.velocity;
                v.y = 0; Body.velocity =v;
                frc.y += JumpFrc;
            }
        } else frc.x *= 0.5f;

        if(JumpTimer > Time.time +0.1f && Input.GetButton("Jump"+PlayerInd) ) {
            frc.y += JumpFrc *Time.deltaTime *2.0f;
        }
        
        frc.y += Gravity*Time.deltaTime;
        Body.AddForce( frc );
    

    }

    bool Crouched = false;
    float JumpTimer = -1;
    //bool Grounded = false;
    float SlowTimer = 0.0f;
    [HideInInspector] public float InvulTimer;
    [HideInInspector] public float ForceTimer;
    int GroundFrameCnt;
/*
    void OnTriggerEnter( Collider other ) {
        OnTriggerStay(other);
    }
    void OnTriggerStay(Collider other ) {
       // if( Vector3.Dot(other.gameObject.transform.position - Trnsfrm.position, Trnsfrm.up ) >0 )
         //   Grounded=true;



    }*/

    public bool Dead { get; private set;}

    public void DieMuthaFucka() {
		audio.PlayOneShot(DeathSound);
        if(Dead )return;
        if( InvulTimer > Time.time )return;
        Dead = true;
        Body.constraints = (RigidbodyConstraints)((int)Body.constraints & 1^(int)RigidbodyConstraints.FreezePositionZ);
        Anim.SetBool("Crouch",  Crouched = false );

        JumpTimer = Time.time +1.5f;

        Col.material = TypPhysMat;

        Body.AddTorque(0,0,Random.Range(-50,50));
    }

	public float IncreasedSpeed = 10.0f;
	public float DurationSpeedBoost = 5.0f;

	public void SpeedBoost(){
		SpeedEffects.SetActive(true);
		float OriginalSpeed = MaxSpeed;
		float TimerStart = Time.time;
		MaxSpeed = IncreasedSpeed;
		if (Time.time-TimerStart > DurationSpeedBoost){
			Debug.Log ("revert");
			MaxSpeed = OriginalSpeed;
			SpeedEffects.SetActive(false);
		}
	}

	public float DurationInvertedControls = 5.0f;

	[HideInInspector] public bool IsInvert = false;
	public void InvertedControls(){
		float TimerStart = Time.time;
		IsInvert = true;
		if(Time.time-TimerStart > DurationSpeedBoost){
			Debug.Log ("revert");
			IsInvert = false;
		}
	}

	public float DurationInvisibility = 5.0f;
	public GameObject Skin;
	public void Invisibility(){
		float TimerStart = Time.time;
			Skin.SetActive(false);
		if(Time.time-TimerStart > DurationSpeedBoost){
			Debug.Log ("revert");
			Skin.SetActive(true);
		}
	}

	IEnumerator DeadSplatter(){
		DeathEffects.SetActive(true);
		yield return new WaitForSeconds(0.5f);
		DeathEffects.SetActive(false);
	}
}
 